<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图像标注工具</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 20px;
            background-color: #f5f5f5;
        }

        #toolbar {
            margin-bottom: 20px;
            padding: 15px;
            background-color: #fff;
            border-radius: 8px;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
            display: flex;
            gap: 15px;
            align-items: center;
        }

        #imageContainer {
            position: relative;
            border: 2px dashed #ccc;
            background-color: #eee;
            overflow: hidden;
            cursor: crosshair;
        }

        #mainCanvas {
            display: block;
        }

        #labelInput {
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }

        button {
            padding: 8px 16px;
            background-color: #007bff;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }

        button:hover {
            background-color: #0056b3;
        }

        button:disabled {
            background-color: #cccccc;
            cursor: not-allowed;
        }

        #annotationList {
            margin-top: 20px;
            width: 800px;
            max-height: 200px;
            overflow-y: auto;
            background-color: #fff;
            border: 1px solid #ddd;
            border-radius: 4px;
            padding: 10px;
        }

        .annotation-item {
            padding: 8px;
            border-bottom: 1px solid #eee;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .annotation-item:last-child {
            border-bottom: none;
        }

        .delete-btn {
            background-color: #dc3545;
            padding: 4px 8px;
            font-size: 12px;
        }

        .delete-btn:hover {
            background-color: #c82333;
        }

        #instructions {
            margin-top: 20px;
            padding: 15px;
            background-color: #e9ecef;
            border-radius: 8px;
            font-size: 14px;
            max-width: 800px;
        }

        #instructions h3 {
            margin-top: 0;
        }

        #instructions ul {
            padding-left: 20px;
        }

        #instructions li {
            margin-bottom: 8px;
        }

        /* 添加加载提示样式 */
        #loadingOverlay {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            display: flex;
            justify-content: center;
            align-items: center;
            color: white;
            font-size: 24px;
            z-index: 10;
            display: none;
        }

        /* 添加文件名显示样式 */
        #filenameDisplay {
            position: absolute;
            top: 10px;
            right: 10px;
            background-color: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 5px 10px;
            border-radius: 4px;
            font-size: 14px;
            z-index: 5;
            display: none;
        }

        /* 添加进度条样式 */
        #progressContainer {
            width: 800px;
            margin-bottom: 15px;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        #progressBar {
            flex: 1;
            height: 10px;
            background-color: #ddd;
            border-radius: 5px;
            cursor: pointer;
            position: relative;
        }

        #progressBar::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            background: #007bff;
            cursor: pointer;
        }

        #progressBar::-moz-range-thumb {
            width: 18px;
            height: 18px;
            border-radius: 50%;
            background: #007bff;
            cursor: pointer;
        }

        #progressFill {
            height: 100%;
            background-color: #007bff;
            border-radius: 5px;
            width: 0%;
        }

        #progressInfo {
            font-size: 14px;
            color: #666;
            min-width: 80px;
            text-align: center;
        }

        /* 添加模型信息显示样式 */
        #modelInfo {
            margin-top: 10px;
            padding: 10px;
            background-color: #e9ecef;
            border-radius: 4px;
            font-size: 14px;
            text-align: center;
        }
    </style>
</head>

<body>
    <h1>图像标注工具</h1>

    <div id="toolbar">
        <button id="annotateBtn" disabled>开始标注 (W)</button>
        <button id="clearBtn">清空所有标注</button>
        <button id="selectFileBtn">获取图片 (O)</button>
        <button id="fullscreenBtn">全屏显示 (F)</button>
    </div>

    <!-- 将进度条移到顶部 -->
    <div id="progressContainer">
        <div id="progressInfo">0/0</div>
        <div id="progressBar">
            <div id="progressFill"></div>
        </div>
    </div>

    <div id="imageContainer">
        <canvas id="mainCanvas"></canvas>
        <!-- 添加加载提示覆盖层 -->
        <div id="loadingOverlay">加载中...</div>
        <!-- 添加文件名显示元素 -->
        <div id="filenameDisplay"></div>
    </div>

    <!-- 添加模型信息显示区域 -->
    <div id="modelInfo">
        模型文件更新时间: <span id="modelModifiedTime">获取中...</span>
    </div>

    <div id="annotationList">
        <h3>标注列表</h3>
        <div id="annotations"></div>
    </div>

    <div id="instructions">
        <h3>功能说明</h3>
        <ul>
            <li><strong>图片导入:</strong> 使用"O"键或点击"获取图片"按钮用于导入远程图片。</li>
            <li><strong>图片切换:</strong> 使用"A"/"D"键或点击左右方向按钮切换上一张/下一张图片。</li>
            <li><strong>图片删除:</strong> 按住Ctrl键并按下Delete键可删除当前图片。</li>
            <li><strong>添加标注:</strong>
                <ol>
                    <li>点击"开始标注"按钮或按快捷键"W"进入标注模式。</li>
                    <li>在图像上按住鼠标左键并拖动，绘制一个矩形框。</li>
                    <li>松开鼠标，自动使用"水草"标签完成标注。</li>
                </ol>
            </li>
            <li><strong>编辑标注:</strong>
                <ol>
                    <li>点击任意标注框可选中该标注。</li>
                    <li>选中后可通过拖拽蓝色手柄调整标注框大小。</li>
                    <li>按Delete键可删除选中的标注。</li>
                </ol>
            </li>
            <li><strong>保存到训练集:</strong> 按"S"键可将当前图片及其标注保存到训练集，并从当前列表中移除。</li>
            <li><strong>其他操作:</strong>
                <ol>
                    <li>点击"清空所有标注"按钮可移除当前图片上的所有标注。</li>
                    <li>系统会自动保存标注结果。</li>
                </ol>
            </li>
        </ul>
    </div>

    <script>
        // 获取DOM元素
        const canvas = document.getElementById('mainCanvas');
        const ctx = canvas.getContext('2d');
        const imageContainer = document.getElementById('imageContainer');
        const annotateBtn = document.getElementById('annotateBtn');
        const clearBtn = document.getElementById('clearBtn');
        const annotationsDiv = document.getElementById('annotations');
        const selectFileBtn = document.getElementById('selectFileBtn');
        // 获取全屏按钮元素
        const fullscreenBtn = document.getElementById('fullscreenBtn');
        // 获取加载提示元素
        const loadingOverlay = document.getElementById('loadingOverlay');
        // 获取进度条相关元素
        const progressBar = document.getElementById('progressBar');
        const progressFill = document.getElementById('progressFill');
        const progressInfo = document.getElementById('progressInfo');

        // 状态变量
        let isDrawing = false;
        let startPoint = { x: 0, y: 0 };
        let currentRect = null;
        let img = null;
        let annotations = [];
        let classNames = []; // 用于存储类别名称
        let selectedAnnotationIndex = -1; // 当前选中的标注索引
        let imageList = []; // 存储从服务器获取的图片列表
        let currentImageIndex = 0; // 当前显示的图片索引
        // 添加标注修改状态跟踪变量
        let annotationsModified = false; // 标注是否被修改
        // 添加调整大小相关变量
        let isResizing = false;
        let resizeHandle = null; // 当前调整大小的手柄位置
        let originalRect = null; // 调整大小前的原始矩形
        // 添加移动相关变量
        let isMoving = false;
        let moveStartPoint = { x: 0, y: 0 };
        let originalPosition = { x: 0, y: 0 };

        // 初始化按钮状态
        updateAnnotateButton();

        // 事件监听器
        annotateBtn.addEventListener('click', toggleAnnotationMode);
        clearBtn.addEventListener('click', clearAllAnnotations);
        selectFileBtn.addEventListener('click', selectEditImagelist);
        // 添加全屏按钮事件监听器
        fullscreenBtn.addEventListener('click', toggleFullscreen);

        canvas.addEventListener('mousedown', startDrawing);
        canvas.addEventListener('mousemove', drawRectangle);
        canvas.addEventListener('mouseup', finishDrawing);
        canvas.addEventListener('mouseleave', finishDrawing); // 鼠标离开画布也结束绘制
        canvas.addEventListener('click', selectAnnotation); // 添加点击选择标注的事件
        // 添加鼠标按下事件用于调整大小
        canvas.addEventListener('mousedown', startResize);
        // 添加鼠标移动事件用于调整大小
        canvas.addEventListener('mousemove', doResize);
        // 添加鼠标释放事件用于结束调整大小
        canvas.addEventListener('mouseup', endResize);

        // 添加触摸事件支持移动端操作
        canvas.addEventListener('touchstart', handleTouchStart);
        canvas.addEventListener('touchmove', handleTouchMove);
        canvas.addEventListener('touchend', handleTouchEnd);

        // 添加进度条点击事件
        progressBar.addEventListener('click', handleProgressClick);

        // 添加键盘事件监听器
        document.addEventListener('keydown', function (e) {
            // 检查是否按下了'O'键
            if (e.key.toLowerCase() === 'o') {
                selectEditImagelist();
            }

            // 添加A/D键切换图片的功能
            if (e.key.toLowerCase() === 'd' && imageList.length > 1) {
                switchImage(1); // 下一张
            }

            if (e.key.toLowerCase() === 'a' && imageList.length > 1) {
                switchImage(-1); // 上一张
            }

            // 检查是否按下了'W'键并且不是在输入框中
            if (e.key.toLowerCase() === 'w') {
                if (!annotateBtn.disabled) {
                    toggleAnnotationMode();
                }
            }
            // 如果按下了ESC键并且正在标注中，则取消标注
            if (e.key === 'Escape' && annotateBtn.textContent === '标注中...') {
                toggleAnnotationMode();
            }
            // 添加Delete键删除选中标注的功能
            if (e.key === 'Delete' && selectedAnnotationIndex !== -1) {
                deleteAnnotation(selectedAnnotationIndex);
                selectedAnnotationIndex = -1;
            }

            // 添加Ctrl+Delete删除当前图片的功能
            if (e.key === 'Delete' && e.ctrlKey) {
                deleteCurrentImage();
            }

            // 添加S键保存到训练集的功能
            if (e.key.toLowerCase() === 's' && img) {
                if (confirm('是否保存到训练集？')) {

                    saveToTrainingSet();
                }
            }

            // 添加F键全屏显示的功能
            if (e.key.toLowerCase() === 'f') {
                toggleFullscreen();
            }
        });

        // 更新"开始标注"按钮状态
        function updateAnnotateButton() {
            if (img) {
                annotateBtn.disabled = false;
                annotateBtn.textContent = '开始标注 (W)';
            } else {
                annotateBtn.disabled = true;
                annotateBtn.textContent = '开始标注 (W)';
            }
        }


        // 切换标注模式
        function toggleAnnotationMode() {
            if (annotateBtn.textContent === '开始标注 (W)') {
                annotateBtn.textContent = '标注中... (ESC取消)';
                annotateBtn.style.backgroundColor = '#ffc107';
                annotateBtn.style.color = '#212529';
                canvas.style.cursor = 'crosshair'; // 设置为十字光标
            } else {
                annotateBtn.textContent = '开始标注 (W)';
                annotateBtn.style.backgroundColor = '';
                annotateBtn.style.color = '';
                canvas.style.cursor = 'default'; // 恢复为默认箭头光标
                // 取消当前未完成的绘制
                if (isDrawing) {
                    isDrawing = false;
                    redrawCanvas();
                }
            }
        }

        // 选择并上传文件的函数
        function selectEditImagelist() {
            // 显示加载提示
            showLoading();

            fetch('/labelimg', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    "imgname": ""
                })
            })
                .then(response => response.json())
                .then(data => {
                    if (data.imglist && data.imglist.length > 0) {
                        imageList = data.imglist;
                        labelList = data.labellist;
                        currentImageIndex = 0;
                        loadCurrentImage();
                    } else {
                        alert('服务器未返回有效的图片数据');
                        hideLoading(); // 隐藏加载提示
                    }
                })
                .catch(error => {
                    hideLoading(); // 隐藏加载提示
                });
        }

        // 上传文件到服务器
        function uploadFiles(files) {
            // 显示加载提示
            showLoading();

            const formData = new FormData();
            for (let i = 0; i < files.length; i++) {
                formData.append('images', files[i]);
            }

            fetch('/labelimg', {
                method: 'POST',
                body: formData
            })
                .then(response => response.json())
                .then(data => {
                    if (data.images && data.images.length > 0) {
                        imageList = data.images;
                        currentImageIndex = 0;
                        loadCurrentImage();
                    } else {
                        alert('服务器未返回有效的图片数据');
                        hideLoading(); // 隐藏加载提示
                    }
                })
                .catch(error => {
                    console.error('Error:', error);
                    alert('上传文件时出错: ' + error.message);
                    hideLoading(); // 隐藏加载提示
                });
        }

        // 加载当前图片
        function loadCurrentImage() {
            if (imageList.length === 0) {
                hideLoading(); // 隐藏加载提示
                return;
            }

            // 显示加载提示
            showLoading();
            canvas.style.cursor = 'wait'; // 设置为等待光标

            // 发送当前标注结果到服务器
            saveCurrentAnnotations();

            const imageName = imageList[currentImageIndex];

            // 显示文件名
            const filenameDisplay = document.getElementById('filenameDisplay');
            filenameDisplay.textContent = imageName;
            filenameDisplay.style.display = 'block';

            // 更新进度条
            updateProgress();

            // 检查图片是否已在缓存中
            if (imageCache[imageName]) {
                // 使用缓存的图片
                img = imageCache[imageName];
                setupCanvasAndLoad();
                // 预加载相邻图片
                preloadImages();
            } else {
                // 正常加载图片
                img = new Image();
                img.onload = function () {
                    // 缓存图片
                    imageCache[imageName] = img;
                    setupCanvasAndLoad();
                    // 预加载相邻图片
                    preloadImages();
                };

                // 处理加载错误
                img.onerror = function () {
                    hideLoading(); // 隐藏加载提示
                    canvas.style.cursor = 'default'; // 恢复默认光标
                };

                img.src = "/labelimg?imgname=" + imageName;
            }
        }

        // 设置画布并加载标注
        function setupCanvasAndLoad() {
            // 设置canvas尺寸与图像一致
            canvas.width = img.width;
            canvas.height = img.height;

            // 如果图片宽度超过屏幕宽度，则按比例缩放
            const maxWidth = window.innerWidth * 0.8; // 最大宽度为屏幕宽度的80%
            if (img.width > maxWidth) {
                const scale = maxWidth / img.width;
                canvas.width = maxWidth;
                canvas.height = img.height * scale;
            }

            imageContainer.style.width = canvas.width + 'px';
            imageContainer.style.height = canvas.height + 'px';

            redrawCanvas();
            updateAnnotateButton(); // 图像加载后检查按钮状态

            // 加载对应的标注文件
            loadLabelData();

            // 隐藏加载提示
            hideLoading();
            // 图片加载完成后恢复默认光标
            if (annotateBtn.textContent === '开始标注 (W)') {
                canvas.style.cursor = 'default';
            } else {
                canvas.style.cursor = 'crosshair';
            }
        }

        // 加载标注数据
        function loadLabelData() {
            // 清空当前标注
            annotations = [];
            selectedAnnotationIndex = -1;
            updateAnnotationList();

            const imageName = imageList[currentImageIndex];
            const labelName = imageName.substring(0, imageName.lastIndexOf('.')) + '.txt';

            fetch(`/labeltxt?labelname=${labelName}&t=${Math.random()}`)
                .then(response => {
                    if (response.ok) {
                        return response.text();
                    }
                    return '';
                })
                .then(data => {
                    if (data) {
                        parseLabelData(data);
                    }
                    redrawCanvas();
                    updateAnnotationList();
                    // 重置修改状态
                    annotationsModified = false;
                })
                .catch(error => {
                    console.error('加载标注文件出错:', error);
                    redrawCanvas();
                    // 重置修改状态
                    annotationsModified = false;
                });
        }

        // 解析标注数据
        function parseLabelData(data) {
            const lines = data.trim().split('\n');
            console.log(lines);
            annotations = [];

            lines.forEach(line => {
                const parts = line.trim().split(' ');
                if (parts.length === 5) {
                    const centerX = parseFloat(parts[1]);
                    const centerY = parseFloat(parts[2]);
                    const width = parseFloat(parts[3]);
                    const height = parseFloat(parts[4]);

                    // 转换为像素坐标
                    const x = (centerX - width / 2) * canvas.width;
                    const y = (centerY - height / 2) * canvas.height;
                    const rectWidth = width * canvas.width;
                    const rectHeight = height * canvas.height;

                    // 默认标签全部为"水草"
                    const label = "水草";
                    console.log(label)
                    annotations.push({
                        x: x,
                        y: y,
                        width: rectWidth,
                        height: rectHeight,
                        label: label
                    });
                }
            });
        }

        // 切换图片
        function switchImage(direction) {
            if (imageList.length <= 1) return;

            // 显示加载提示
            showLoading();
            canvas.style.cursor = 'wait'; // 设置为等待光标

            // 保存当前标注
            saveCurrentAnnotations();

            // 更新索引
            currentImageIndex += direction;
            if (currentImageIndex >= imageList.length) {
                currentImageIndex = 0;
            } else if (currentImageIndex < 0) {
                currentImageIndex = imageList.length - 1;
            }

            // 清空当前标注
            annotations = [];
            selectedAnnotationIndex = -1;
            updateAnnotationList();

            // 加载新图片
            loadCurrentImage();
        }

        // 保存当前标注结果到服务器
        function saveCurrentAnnotations() {
            // 只有在标注被修改时才发送请求
            if (!img || !annotationsModified) return;

            const yoloContent = generateYOLOAnnotations();
            console.log(yoloContent);
            const imageName = getImageNameFromUrl(imageList[currentImageIndex]);
            const labelName = imageName.substring(0, imageName.lastIndexOf('.')) + '.txt';

            fetch('/labeltxt', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    labelname: labelName,
                    labeltxt: yoloContent
                })
            })
                .then(response => {
                    if (!response.ok) {
                        console.error('保存标注失败');
                    } else {
                        console.log('保存成功');
                        // 保存成功后重置修改状态
                        annotationsModified = false;
                    }
                })
                .catch(error => {
                    console.error('保存标注时出错:', error);
                });
        }

        // 从URL中提取图片名称
        function getImageNameFromUrl(url) {
            return url.substring(url.lastIndexOf('/') + 1);
        }

        // 开始绘制矩形
        function startDrawing(e) {
            if (annotateBtn.textContent !== '标注中... (ESC取消)' || !img) return;

            const rect = canvas.getBoundingClientRect();
            startPoint.x = e.clientX - rect.left;
            startPoint.y = e.clientY - rect.top;
            isDrawing = true;
            // 使用固定标签"水草"作为默认标注文本
            const defaultLabel = "水草";
            currentRect = {
                x: startPoint.x,
                y: startPoint.y,
                width: 0,
                height: 0,
                label: defaultLabel
            };
        }

        // 绘制矩形(鼠标移动时)
        function drawRectangle(e) {
            if (!isDrawing || !img) return;

            const rect = canvas.getBoundingClientRect();
            const currentX = e.clientX - rect.left;
            const currentY = e.clientY - rect.top;

            currentRect.width = currentX - startPoint.x;
            currentRect.height = currentY - startPoint.y;

            redrawCanvas();
            drawCurrentRect();
        }

        // 完成绘制矩形
        function finishDrawing() {
            if (!isDrawing || !img) return;

            isDrawing = false;

            // 标准化矩形坐标(确保width和height为正)
            if (currentRect.width < 0) {
                currentRect.x += currentRect.width;
                currentRect.width = Math.abs(currentRect.width);
            }
            if (currentRect.height < 0) {
                currentRect.y += currentRect.height;
                currentRect.height = Math.abs(currentRect.height);
            }

            // 添加到标注数组
            if (currentRect.width > 5 && currentRect.height > 5) { // 避免误触
                annotations.push({ ...currentRect });
                addAnnotationToList(annotations.length - 1);
                // 标记标注已修改
                annotationsModified = true;
            }

            currentRect = null;
            redrawCanvas();
            // 自动结束标注模式
            toggleAnnotationMode();
        }

        // 重绘Canvas基础内容
        function redrawCanvas() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            if (img) {
                // 在全屏模式下保持图片比例并适应屏幕
                if (document.fullscreenElement) {
                    const containerWidth = document.fullscreenElement.clientWidth;
                    const containerHeight = document.fullscreenElement.clientHeight;

                    // 计算缩放比例以适应屏幕
                    const scaleX = containerWidth / img.width;
                    const scaleY = containerHeight / img.height;
                    const scale = Math.min(scaleX, scaleY);

                    // 计算居中位置
                    const width = img.width * scale;
                    const height = img.height * scale;
                    const x = (containerWidth - width) / 2;
                    const y = (containerHeight - height) / 2;

                    // 更新canvas尺寸
                    canvas.width = containerWidth;
                    canvas.height = containerHeight;
                    imageContainer.style.width = containerWidth + 'px';
                    imageContainer.style.height = containerHeight + 'px';

                    // 绘制居中图片
                    ctx.drawImage(img, x, y, width, height);
                } else {
                    // 非全屏模式保持原有逻辑
                    ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
                }
            }
            // 重绘所有已保存的标注
            annotations.forEach((ann, index) => {
                drawAnnotation(ann, index === selectedAnnotationIndex);
            });
        }

        // 全屏切换功能
        function toggleFullscreen() {
            if (!img) return;

            if (!document.fullscreenElement) {
                // 进入全屏
                if (imageContainer.requestFullscreen) {
                    imageContainer.requestFullscreen();
                } else if (imageContainer.webkitRequestFullscreen) {
                    imageContainer.webkitRequestFullscreen();
                } else if (imageContainer.msRequestFullscreen) {
                    imageContainer.msRequestFullscreen();
                }
                fullscreenBtn.textContent = '退出全屏 (F)';
            } else {
                // 退出全屏
                if (document.exitFullscreen) {
                    document.exitFullscreen();
                } else if (document.webkitExitFullscreen) {
                    document.webkitExitFullscreen();
                } else if (document.msExitFullscreen) {
                    document.msExitFullscreen();
                }
                fullscreenBtn.textContent = '全屏显示 (F)';
            }
        }

        // 监听全屏状态变化
        document.addEventListener('fullscreenchange', handleFullscreenChange);
        document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
        document.addEventListener('msfullscreenchange', handleFullscreenChange);

        function handleFullscreenChange() {
            if (!document.fullscreenElement) {
                fullscreenBtn.textContent = '全屏显示 (F)';
            }
        }

        // 绘制当前正在绘制的矩形
        function drawCurrentRect() {
            if (currentRect) {
                ctx.beginPath();
                ctx.rect(currentRect.x, currentRect.y, currentRect.width, currentRect.height);
                ctx.setLineDash([5, 3]); // 虚线
                ctx.strokeStyle = 'red';
                ctx.lineWidth = 2;
                ctx.stroke();
                ctx.setLineDash([]); // 恢复实线

                // 绘制标签
                if (currentRect.label) {
                    ctx.font = '14px Arial';
                    const textWidth = ctx.measureText(currentRect.label).width;
                    const textHeight = 14; // 近似高度
                    ctx.fillStyle = 'transparent';
                    ctx.fillRect(currentRect.x, currentRect.y - textHeight - 4, textWidth + 6, textHeight + 4);
                    ctx.fillStyle = 'black';
                    ctx.fillText(currentRect.label, currentRect.x + 3, currentRect.y - 3);
                }
            }
        }

        // 绘制单个标注
        function drawAnnotation(annotation, isSelected = false) {
            ctx.beginPath();
            ctx.rect(annotation.x, annotation.y, annotation.width, annotation.height);
            ctx.setLineDash([]); // 确保是实线
            ctx.strokeStyle = isSelected ? 'blue' : 'red'; // 选中的标注用蓝色显示
            ctx.lineWidth = isSelected ? 3 : 2; // 选中的标注线条更粗
            ctx.stroke();

            // 绘制标签
            if (annotation.label) {
                ctx.font = '14px Arial';
                const textWidth = ctx.measureText(annotation.label).width;
                const textHeight = 14;
                ctx.fillStyle = 'transparent';
                ctx.fillRect(annotation.x, annotation.y - textHeight - 4, textWidth + 6, textHeight + 4);
                ctx.fillStyle = 'black';
                ctx.fillText(annotation.label, annotation.x + 3, annotation.y - 3);
            }

            // 如果标注被选中，绘制调整手柄
            if (isSelected) {
                const handleSize = 5;
                ctx.fillStyle = 'blue';

                // 绘制四个角的手柄
                // 西北角
                ctx.fillRect(annotation.x - handleSize / 2, annotation.y - handleSize / 2, handleSize, handleSize);
                // 东北角
                ctx.fillRect(annotation.x + annotation.width - handleSize / 2, annotation.y - handleSize / 2, handleSize, handleSize);
                // 西南角
                ctx.fillRect(annotation.x - handleSize / 2, annotation.y + annotation.height - handleSize / 2, handleSize, handleSize);
                // 东南角
                ctx.fillRect(annotation.x + annotation.width - handleSize / 2, annotation.y + annotation.height - handleSize / 2, handleSize, handleSize);
            }
        }

        // 点击选择标注
        function selectAnnotation(e) {
            if (!img || annotations.length === 0) return;

            const rect = canvas.getBoundingClientRect();
            const clickX = e.clientX - rect.left;
            const clickY = e.clientY - rect.top;

            // 从后往前查找（后绘制的在上层）
            for (let i = annotations.length - 1; i >= 0; i--) {
                const ann = annotations[i];
                if (clickX >= ann.x && clickX <= ann.x + ann.width &&
                    clickY >= ann.y && clickY <= ann.y + ann.height) {
                    selectedAnnotationIndex = i;
                    redrawCanvas();
                    return;
                }
            }

            // 点击空白处取消选择
            if (selectedAnnotationIndex !== -1) {
                selectedAnnotationIndex = -1;
                redrawCanvas();
            }
        }

        // 检查鼠标是否在调整手柄附近
        function getResizeHandle(x, y, annotation) {
            const handleSize = 6;
            // 检查四个角
            if (Math.abs(x - annotation.x) <= handleSize && Math.abs(y - annotation.y) <= handleSize) {
                return 'nw'; // 西北角
            }
            if (Math.abs(x - (annotation.x + annotation.width)) <= handleSize && Math.abs(y - annotation.y) <= handleSize) {
                return 'ne'; // 东北角
            }
            if (Math.abs(x - annotation.x) <= handleSize && Math.abs(y - (annotation.y + annotation.height)) <= handleSize) {
                return 'sw'; // 西南角
            }
            if (Math.abs(x - (annotation.x + annotation.width)) <= handleSize && Math.abs(y - (annotation.y + annotation.height)) <= handleSize) {
                return 'se'; // 东南角
            }
            return null;
        }

        // 开始调整大小
        function startResize(e) {
            if (!img || selectedAnnotationIndex === -1 || isDrawing) return;

            const rect = canvas.getBoundingClientRect();
            const mouseX = e.clientX - rect.left;
            const mouseY = e.clientY - rect.top;

            const annotation = annotations[selectedAnnotationIndex];
            const handle = getResizeHandle(mouseX, mouseY, annotation);

            if (handle) {
                isResizing = true;
                resizeHandle = handle;
                originalRect = { ...annotation };
                e.preventDefault(); // 防止默认行为
            }
        }

        // 执行调整大小
        function doResize(e) {
            if (!isResizing || !img || selectedAnnotationIndex === -1) return;

            const rect = canvas.getBoundingClientRect();
            const mouseX = e.clientX - rect.left;
            const mouseY = e.clientY - rect.top;

            const annotation = annotations[selectedAnnotationIndex];

            // 根据不同的手柄调整矩形
            switch (resizeHandle) {
                case 'nw': // 西北角 - 同时调整x, y, width, height
                    annotation.width = originalRect.x + originalRect.width - mouseX;
                    annotation.height = originalRect.y + originalRect.height - mouseY;
                    annotation.x = mouseX;
                    annotation.y = mouseY;
                    break;
                case 'ne': // 东北角 - 调整width, y, height
                    annotation.width = mouseX - originalRect.x;
                    annotation.height = originalRect.y + originalRect.height - mouseY;
                    annotation.y = mouseY;
                    break;
                case 'sw': // 西南角 - 调整x, width, height
                    annotation.width = originalRect.x + originalRect.width - mouseX;
                    annotation.height = mouseY - originalRect.y;
                    annotation.x = mouseX;
                    break;
                case 'se': // 东南角 - 调整width, height
                    annotation.width = mouseX - originalRect.x;
                    annotation.height = mouseY - originalRect.y;
                    break;
            }

            // 确保宽度和高度为正数
            if (annotation.width < 0) {
                annotation.x += annotation.width;
                annotation.width = Math.abs(annotation.width);
            }
            if (annotation.height < 0) {
                annotation.y += annotation.height;
                annotation.height = Math.abs(annotation.height);
            }

            redrawCanvas();
            // 标记标注已修改
            annotationsModified = true;
            e.preventDefault();
        }

        // 结束调整大小
        function endResize(e) {
            if (isResizing) {
                isResizing = false;
                resizeHandle = null;
                originalRect = null;
                updateAnnotationList();
                e.preventDefault();
            }
        }

        // 添加标注到列表
        function addAnnotationToList(index) {
            //console.log(annotations)
            const ann = annotations[index];
            const itemDiv = document.createElement('div');
            itemDiv.className = 'annotation-item';

            // 计算YOLO格式
            const centerX = (ann.x + ann.width / 2) / canvas.width;
            const centerY = (ann.y + ann.height / 2) / canvas.height;
            const normWidth = ann.width / canvas.width;
            const normHeight = ann.height / canvas.height;

            // 类别索引全部为0
            const classIndex = 0;

            itemDiv.innerHTML = `
                <span>类别${classIndex}: ${ann.label} → ${classIndex} ${centerX.toFixed(6)} ${centerY.toFixed(6)} ${normWidth.toFixed(6)} ${normHeight.toFixed(6)}</span>
                <button class="delete-btn" data-index="${index}">删除</button>
            `;
            annotationsDiv.appendChild(itemDiv);

            // 为新添加的删除按钮添加事件监听器
            itemDiv.querySelector('.delete-btn').addEventListener('click', function () {
                const idx = parseInt(this.getAttribute('data-index'));
                deleteAnnotation(idx);
            });
        }

        // 删除单个标注
        function deleteAnnotation(index) {
            annotations.splice(index, 1);
            // 更新选中索引
            if (selectedAnnotationIndex === index) {
                selectedAnnotationIndex = -1;
            } else if (selectedAnnotationIndex > index) {
                selectedAnnotationIndex--;
            }
            updateAnnotationList(); // 重新生成列表以更新索引
            redrawCanvas();
            // 标记标注已修改
            annotationsModified = true;
        }

        // 清空所有标注
        function clearAllAnnotations() {
            if (confirm('确定要清空所有标注吗？')) {
                annotations = [];
                selectedAnnotationIndex = -1; // 清空选中状态
                updateAnnotationList();
                redrawCanvas();
                // 标记标注已修改
                annotationsModified = true;
            }
        }

        // 更新整个标注列表
        function updateAnnotationList() {
            annotationsDiv.innerHTML = '<h3>YOLO格式: 类别 中心点x 中心点y 宽 高</h3>';
            annotations.forEach((_, index) => {
                addAnnotationToList(index);
            });
        }

        // 生成YOLO格式的标注内容
        function generateYOLOAnnotations() {
            // 生成YOLO格式的标注行
            const yoloLines = annotations.map(ann => {
                // 计算YOLO格式的中心点和宽高(归一化到0-1)
                const centerX = (ann.x + ann.width / 2) / canvas.width;
                const centerY = (ann.y + ann.height / 2) / canvas.height;
                const normWidth = ann.width / canvas.width;
                const normHeight = ann.height / canvas.height;

                // 类别索引全部为0
                const classIndex = 0;

                // 返回YOLO格式: class_index center_x center_y width height
                return `${classIndex} ${centerX.toFixed(6)} ${centerY.toFixed(6)} ${normWidth.toFixed(6)} ${normHeight.toFixed(6)}`;
            });

            return yoloLines.join('\n');
        }

        // 显示加载提示
        function showLoading(isSaving = false) {
            loadingOverlay.style.display = 'flex';
            loadingOverlay.textContent = isSaving ? '保存中...' : '加载中...';
        }

        // 隐藏加载提示
        function hideLoading() {
            loadingOverlay.style.display = 'none';
            loadingOverlay.textContent = '加载中...'; // 恢复默认文本
        }

        // 初始提示
        ctx.font = '20px Arial';
        ctx.fillStyle = 'gray';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText('图片区域', canvas.width / 2, canvas.height / 2);

        // 添加触摸事件处理函数
        function handleTouchStart(e) {
            e.preventDefault();
            if (e.touches.length > 0) {
                const touch = e.touches[0];
                const mouseEvent = new MouseEvent('mousedown', {
                    clientX: touch.clientX,
                    clientY: touch.clientY
                });
                canvas.dispatchEvent(mouseEvent);
            }
        }

        function handleTouchMove(e) {
            e.preventDefault();
            if (e.touches.length > 0) {
                const touch = e.touches[0];
                const mouseEvent = new MouseEvent('mousemove', {
                    clientX: touch.clientX,
                    clientY: touch.clientY
                });
                canvas.dispatchEvent(mouseEvent);
            }
        }

        function handleTouchEnd(e) {
            e.preventDefault();
            const mouseEvent = new MouseEvent('mouseup', {});
            canvas.dispatchEvent(mouseEvent);
        }

        // 添加鼠标移动事件用于移动选中的box
        canvas.addEventListener('mousemove', function (e) {
            if (isMoving && selectedAnnotationIndex !== -1) {
                moveAnnotation(e);
            } else if (!isDrawing && !isResizing && selectedAnnotationIndex !== -1) {
                // 检查是否需要显示移动手型
                checkMouseMoveCursor(e);
            }
        });

        // 检查是否需要显示移动手型光标
        function checkMouseMoveCursor(e) {
            const rect = canvas.getBoundingClientRect();
            const mouseX = e.clientX - rect.left;
            const mouseY = e.clientY - rect.top;

            const annotation = annotations[selectedAnnotationIndex];
            if (annotation &&
                mouseX >= annotation.x &&
                mouseX <= annotation.x + annotation.width &&
                mouseY >= annotation.y &&
                mouseY <= annotation.y + annotation.height) {
                // 检查是否在调整手柄上
                const handle = getResizeHandle(mouseX, mouseY, annotation);
                if (!handle) {
                    canvas.style.cursor = 'grab';
                } else {
                    canvas.style.cursor = 'crosshair';
                }
            } else {
                canvas.style.cursor = 'default'; // 改为默认箭头光标
            }
        }

        // 开始移动选中的标注
        function startMove(e) {
            if (!img || selectedAnnotationIndex === -1 || isDrawing || isResizing) return;

            const rect = canvas.getBoundingClientRect();
            const mouseX = e.clientX - rect.left;
            const mouseY = e.clientY - rect.top;

            const annotation = annotations[selectedAnnotationIndex];
            if (annotation &&
                mouseX >= annotation.x &&
                mouseX <= annotation.x + annotation.width &&
                mouseY >= annotation.y &&
                mouseY <= annotation.y + annotation.height) {

                // 检查是否点击在调整手柄上
                const handle = getResizeHandle(mouseX, mouseY, annotation);
                if (handle) return; // 如果在手柄上，不执行移动

                isMoving = true;
                moveStartPoint.x = mouseX;
                moveStartPoint.y = mouseY;
                originalPosition.x = annotation.x;
                originalPosition.y = annotation.y;
                canvas.style.cursor = 'grabbing';
                e.preventDefault();
            }
        }

        // 移动标注
        function moveAnnotation(e) {
            if (!isMoving || selectedAnnotationIndex === -1) return;

            const rect = canvas.getBoundingClientRect();
            const mouseX = e.clientX - rect.left;
            const mouseY = e.clientY - rect.top;

            const annotation = annotations[selectedAnnotationIndex];
            const dx = mouseX - moveStartPoint.x;
            const dy = mouseY - moveStartPoint.y;

            annotation.x = originalPosition.x + dx;
            annotation.y = originalPosition.y + dy;

            redrawCanvas();
            annotationsModified = true;
            e.preventDefault();
        }

        // 结束移动
        function endMove() {
            if (isMoving) {
                isMoving = false;
                if (annotateBtn.textContent === '标注中... (ESC取消)') {
                    canvas.style.cursor = 'crosshair'; // 保持十字光标
                } else {
                    canvas.style.cursor = 'default'; // 恢复默认光标
                }
                updateAnnotationList();
            }
        }

        // 修改mousedown事件监听器，添加移动功能
        canvas.addEventListener('mousedown', function (e) {
            startDrawing(e);
            startResize(e);
            startMove(e);
        });

        // 修改mouseup事件监听器，添加结束移动功能
        canvas.addEventListener('mouseup', function (e) {
            finishDrawing();
            endResize(e);
            endMove();
        });

        // 删除当前图片
        function deleteCurrentImage() {
            if (imageList.length === 0) return;

            if (confirm('确定要删除当前图片吗？')) {
                const imageName = imageList[currentImageIndex];
                const labelName = imageName.substring(0, imageName.lastIndexOf('.')) + '.txt';

                // 发送删除请求到服务器
                fetch('/labeltxt', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({
                        labelname: labelName,
                        labeltxt: 'DEL'
                    })
                })
                    .then(response => {
                        if (response.ok) {
                            // 从图片列表中移除当前图片
                            imageList.splice(currentImageIndex, 1);

                            // 如果删除的是最后一张图片，索引前移
                            if (currentImageIndex >= imageList.length && imageList.length > 0) {
                                currentImageIndex = imageList.length - 1;
                            }

                            // 如果还有图片，加载下一张图片
                            if (imageList.length > 0) {
                                loadCurrentImage();
                            } else {
                                // 如果没有图片了，清空画布
                                ctx.clearRect(0, 0, canvas.width, canvas.height);
                                img = null;
                                annotations = [];
                                updateAnnotationList();
                                updateAnnotateButton();

                                // 重置画布提示
                                ctx.font = '20px Arial';
                                ctx.fillStyle = 'gray';
                                ctx.textAlign = 'center';
                                ctx.textBaseline = 'middle';
                                ctx.fillText('图片区域', canvas.width / 2, canvas.height / 2);
                            }
                        } else {
                            alert('删除图片失败');
                        }
                    })
                    .catch(error => {
                        console.error('删除图片时出错:', error);
                        alert('删除图片时出错: ' + error.message);
                    });
            }
        }

        // 添加保存到训练集的函数
        function saveToTrainingSet() {
            const imageName = imageList[currentImageIndex];
            const labelName = imageName.substring(0, imageName.lastIndexOf('.')) + '.txt';

            // 如果标注已修改，先保存标注
            if (annotationsModified) {
                // 显示加载提示
                showLoading();

                const yoloContent = generateYOLOAnnotations();

                fetch('/labeltxt', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({
                        labelname: labelName,
                        labeltxt: yoloContent
                    })
                })
                    .then(response => {
                        if (!response.ok) {
                            console.error('保存标注失败');
                            hideLoading();
                            return;
                        }

                        console.log('保存成功');
                        // 保存成功后重置修改状态
                        annotationsModified = false;

                        // 继续执行移动到训练集的操作
                        moveToTrainingSet(imageName, labelName);
                    })
                    .catch(error => {
                        console.error('保存标注时出错:', error);
                        hideLoading();
                    });
            } else {
                // 如果没有修改，直接执行移动到训练集的操作
                moveToTrainingSet(imageName, labelName);
            }
        }

        // 添加移动到训练集的实际操作
        function moveToTrainingSet(imageName, labelName) {
            fetch('/labeltxt', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    labelname: labelName,
                    labeltxt: 'MOVE'
                })
            })
                .then(response => {
                    if (response.ok) {
                        console.log('成功保存到训练集');
                        // 从图片列表中移除当前图片
                        imageList.splice(currentImageIndex, 1);

                        // 如果删除的是最后一张图片，索引前移
                        if (currentImageIndex >= imageList.length && imageList.length > 0) {
                            currentImageIndex = imageList.length - 1;
                        }

                        // 如果还有图片，加载下一张图片，保持全屏状态
                        if (imageList.length > 0) {
                            loadCurrentImage();
                        } else {
                            // 如果没有图片了，清空画布
                            ctx.clearRect(0, 0, canvas.width, canvas.width);
                            img = null;
                            annotations = [];
                            updateAnnotationList();
                            updateAnnotateButton();

                            // 重置画布提示
                            ctx.font = '20px Arial';
                            ctx.fillStyle = 'gray';
                            ctx.textAlign = 'center';
                            ctx.textBaseline = 'middle';
                            ctx.fillText('图片区域', canvas.width / 2, canvas.height / 2);
                        }
                    } else {
                        console.error('保存到训练集失败');
                    }
                    // 隐藏加载提示，但不退出全屏
                    hideLoading();
                })
                .catch(error => {
                    console.error('保存到训练集时出错:', error);
                    // 隐藏加载提示，但不退出全屏
                    hideLoading();
                });
        }

        // 添加图片缓存对象
        let imageCache = {};

        // 预加载图片函数
        function preloadImages() {
            if (imageList.length <= 1) return;

            // 预加载前一张和后一张图片
            const prevIndex = (currentImageIndex - 1 + imageList.length) % imageList.length;
            const nextIndex = (currentImageIndex + 1) % imageList.length;

            // 预加载前一张图片
            preloadImage(prevIndex);

            // 预加载后一张图片
            preloadImage(nextIndex);
        }

        // 预加载单张图片
        function preloadImage(index) {
            const imageName = imageList[index];

            // 如果图片已经缓存，直接返回
            if (imageCache[imageName]) {
                return;
            }

            // 创建新的图片对象并缓存
            const preloadImg = new Image();
            preloadImg.onload = function () {
                imageCache[imageName] = preloadImg;
            };
            preloadImg.src = "/labelimg?imgname=" + imageName;
        }

        // 更新进度条
        function updateProgress() {
            if (imageList.length === 0) {
                progressInfo.textContent = '0/0';
                progressFill.style.width = '0%';
                return;
            }

            const current = currentImageIndex + 1;
            const total = imageList.length;
            progressInfo.textContent = `${current}/${total}`;

            const percent = (current / total) * 100;
            progressFill.style.width = `${percent}%`;
        }

        // 处理进度条点击事件
        function handleProgressClick(e) {
            if (imageList.length <= 1) return;

            const rect = progressBar.getBoundingClientRect();
            const pos = (e.clientX - rect.left) / rect.width;
            const targetIndex = Math.floor(pos * imageList.length);

            // 确保索引在有效范围内
            const newIndex = Math.max(0, Math.min(imageList.length - 1, targetIndex));

            // 如果点击的是当前图片，则不处理
            if (newIndex === currentImageIndex) return;

            // 显示加载提示
            showLoading();
            canvas.style.cursor = 'wait'; // 设置为等待光标

            // 保存当前标注
            saveCurrentAnnotations();

            // 更新索引
            currentImageIndex = newIndex;

            // 清空当前标注
            annotations = [];
            selectedAnnotationIndex = -1;
            updateAnnotationList();

            // 加载新图片
            loadCurrentImage();
        }

        // 页面加载时获取模型信息
        window.addEventListener('DOMContentLoaded', function () {
            fetch('/modelinfo')
                .then(response => response.json())
                .then(data => {
                    if (data.respdata && data.respdata.modified_time) {
                        document.getElementById('modelModifiedTime').textContent = data.respdata.modified_time;
                    } else {
                        document.getElementById('modelModifiedTime').textContent = '无法获取模型信息';
                    }
                })
                .catch(error => {
                    console.error('获取模型信息出错:', error);
                    document.getElementById('modelModifiedTime').textContent = '获取失败';
                });
        });

    </script>

    <!-- 在现有HTML文件中的适当位置添加以下代码 -->
    <!-- 添加JavaScript函数处理清空操作 -->
    <script>
        function clearAllLabels() {
            if (confirm("警告：确定要清空所有标注文件吗？此操作不可恢复！")) {
                fetch('/labeltxt', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({
                        labelname: 'del',
                        labeltxt: 'DELALL'
                    })
                })
                    .then(response => response.json())
                    .then(data => {
                        if (data.respdata === "all deleted") {
                            alert("所有标注文件已清空！");
                            location.reload(); // 刷新页面
                        } else {
                            alert("清空操作失败：" + data.respdata);
                        }
                    })
                    .catch(error => {
                        console.error('Error:', error);
                        alert("清空操作失败");
                    });
            }
        }
    </script>

    <!-- 在页面底部添加按钮 -->
    <div style="position: fixed; bottom: 20px; right: 20px;">
        <button onclick="clearAllLabels()" style="background-color: #ff4444; color: white; padding: 10px 20px; 
                       border: none; border-radius: 5px; cursor: pointer;
                       font-size: 16px; box-shadow: 0 2px 5px rgba(0,0,0,0.2);">
            全部清空
        </button>
    </div>

</body>

</html>